﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Bluyel.Core
{
    /// <summary>
    /// Type finder (search) manager.
    /// </summary>
    public class TypeFinderBase
    {
        TypeMgrBase _typeMgr;

        //TypePhyMgr _typePhyMgr;


        //=====================================================================
        #region Constructor.

        //---------------------------------------------------------------------
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="factory"></param>
        public TypeFinderBase(TypeMgrBase typeMgr) //, TypePhyMgr typePhyMgr)
        {
            _typeMgr = typeMgr;
            //_typePhyMgr= typePhyMgr;
        }
        #endregion

        //=====================================================================
        #region Properties.

        //---------------------------------------------------------------------
        /// <summary>
        /// return all defined types.
        /// </summary>
        public IEnumerable<IType> ListType
        {
            get
            {
                List<IType> list = new List<IType>();
                list.AddRange(_typeMgr.ListTypeBasic);
                list.AddRange(_typeMgr.ListTypeEnum);
                list.Add(_typeMgr.TypeStruct);

                list.Add(_typeMgr.TypePhyLength);
                return list;
            }
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// return all defined types basics.
        /// </summary>
        public IEnumerable<ITypeBasic> ListTypeBasic
        {
            get
            {
                return _typeMgr.ListTypeBasic;
            }
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// return all defined types enumeration.
        /// </summary>
        public IEnumerable<ITypeEnum> ListTypeEnum
        {
            get
            {
                return _typeMgr.ListTypeEnum;
            }
        }
        #endregion

        //=====================================================================
        #region Public Get/Set methods.

        //---------------------------------------------------------------------
        public ITypeBasic GetTypeInt()
        {
            return _typeMgr.TypeInt;
        }

        //---------------------------------------------------------------------
        public ITypeBasic GetTypeLong()
        {
            return _typeMgr.TypeLong;
        }

        //---------------------------------------------------------------------
        public ITypeBasic GetTypeDouble()
        {
            return _typeMgr.TypeDouble;
        }

        //---------------------------------------------------------------------
        public ITypeBasic GetTypeString()
        {
            return _typeMgr.TypeString;
        }

        //---------------------------------------------------------------------
        public ITypeBasic GetTypeBool()
        {
            return _typeMgr.TypeBool;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Get the Structure type.
        /// </summary>
        /// <returns></returns>
        public ITypeStruct GetTypeStruct()
        {
            return _typeMgr.TypeStruct;
        }

        ////---------------------------------------------------------------------
        ///// <summary>
        ///// return the physical qty type, from the prefix.
        ///// Provide the speci
        ///// </summary>
        ///// <param name="qty"></param>
        ///// <returns></returns>
        //public ITypePhy GetTypePhy(TypePhyQuantity qty)
        //{
        //    if (qty == TypePhyQuantity.Length)
        //        return GetTypePhyLength();

        //    // implement others quantity
        //    // TODO:

        //    return null;

        //}

        //---------------------------------------------------------------------
        /// <summary>
        /// return the physical qty type, from the prefix.
        /// Provide the speci
        /// </summary>
        /// <param name="qty"></param>
        /// <returns></returns>
        public ITypePhy GetTypePhyLength()
        {
            return _typeMgr.TypePhyLength;
        }

        #endregion

        //=====================================================================
        #region Public GetTypeOf methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Get the type of the dataValue.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public IType GetTypeOfValue(IValue value)
        {
            ValueBool dvBool = value as ValueBool;
            if (dvBool != null) return GetTypeBool();

            ValueInt dvInt = value as ValueInt;
            if (dvInt != null) return GetTypeInt();

            ValueLong dvLong = value as ValueLong;
            if (dvLong != null) return GetTypeLong();

            ValueDouble dvDbl = value as ValueDouble;
            if (dvDbl != null) return GetTypeDouble();

            ValueString dvStr = value as ValueString;
            if (dvStr != null) return GetTypeString();

            return null;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Get the type of the dataValue.
        /// </summary>
        /// <param name="dataValue"></param>
        /// <returns></returns>
        public IType GetTypeOfData(IDataNamed dataNamed)
        {
            if (dataNamed == null)
                return null;
            return dataNamed.Type;
        }
        #endregion

        //=====================================================================
        #region Public Is on Type methods.

        //---------------------------------------------------------------------
        public bool IsTypeInt(IType type)
        {
            if (type == null)
                return false;

            if (type.Id.IdAreEquals(TypeDef.TypeIntId))
                return true;

            return false;
        }
        //---------------------------------------------------------------------
        public bool IsTypeLong(IType type)
        {
            if (type == null)
                return false;

            if (type.Id.IdAreEquals(TypeDef.TypeLongId))
                return true;

            return false;
        }
        //---------------------------------------------------------------------
        public bool IsTypeDouble(IType type)
        {
            if (type == null)
                return false;

            if (type.Id.IdAreEquals(TypeDef.TypeDoubleId))
                return true;

            return false;
        }
        //---------------------------------------------------------------------
        public bool IsTypeString(IType type)
        {
            if (type == null)
                return false;

            if (type.Id.IdAreEquals(TypeDef.TypeStringId))
                return true;

            return false;
        }

        //---------------------------------------------------------------------
        public bool IsTypeBool(IType type)
        {
            if (type == null)
                return false;

            if (type.Id.IdAreEquals(TypeDef.TypeBoolId))
                return true;

            return false;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Check that types are same.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="dataValue"></param>
        /// <returns></returns>
        public bool AreSameType(IDBasic data, IValueBasic dataValue)
        {
            if (data == null)
                return false;
            if (dataValue == null)
                return false;
            if (data.Type.Id == GetTypeOfValue(dataValue).Id)
                return true;

            return false;
        }
        #endregion

        //=====================================================================
        #region Public Is on DataValue methods.

        //---------------------------------------------------------------------
        public bool IsTypeInt(IValue dv)
        {
            if (dv == null)
                return false;

            return IsTypeInt(GetTypeOfValue(dv));
        }

        //---------------------------------------------------------------------
        public bool IsTypeLong(IValue dv)
        {
            if (dv == null)
                return false;

            return IsTypeLong(GetTypeOfValue(dv));
        }
        //---------------------------------------------------------------------
        public bool IsTypeDouble(IValue dv)
        {
            if (dv == null)
                return false;

            return IsTypeDouble(GetTypeOfValue(dv));
        }
        //---------------------------------------------------------------------
        public bool IsTypeString(IValue dv)
        {
            if (dv == null)
                return false;

            return IsTypeString(GetTypeOfValue(dv));
        }
        //---------------------------------------------------------------------
        public bool IsTypeBool(IValue dv)
        {
            if (dv == null)
                return false;

            return IsTypeBool(GetTypeOfValue(dv));
        }

        #endregion

        //=====================================================================
        #region Public Is on DataNamed (var/const) methods.

        //---------------------------------------------------------------------
        public bool IsTypeInt(IDataNamed dv)
        {
            if (dv == null)
                return false;

            return IsTypeInt(GetTypeOfData(dv));
        }

        //---------------------------------------------------------------------
        public bool IsTypeLong(IDataNamed dv)
        {
            if (dv == null)
                return false;

            return IsTypeLong(GetTypeOfData(dv));
        }
        //---------------------------------------------------------------------
        public bool IsTypeDouble(IDataNamed dv)
        {
            if (dv == null)
                return false;

            return IsTypeDouble(GetTypeOfData(dv));
        }
        //---------------------------------------------------------------------
        public bool IsTypeString(IDataNamed dv)
        {
            if (dv == null)
                return false;

            return IsTypeString(GetTypeOfData(dv));
        }
        //---------------------------------------------------------------------
        public bool IsTypeBool(IDataNamed dv)
        {
            if (dv == null)
                return false;

            return IsTypeBool(GetTypeOfData(dv));
        }

        #endregion

        //=====================================================================
        #region Public Find Type methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Find a type by the name, look in each part: basic type, lov type,...
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public IType FindTypeByName(string name)
        {
            if(string.IsNullOrWhiteSpace(name))
                return null;

            // is it a type basic?
            ITypeBasic typeBasic = FindTypeBasicByName(name);
            if (typeBasic != null)
                return typeBasic;

            // is it the type dataStruct?
            if (_typeMgr.TypeStruct != null)
            {
                if (_typeMgr.TypeStruct.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                    return _typeMgr.TypeStruct;
            }

            // is it a type LOV?
            ITypeEnum typeLOV = FindTypeEnumByName(name);
            if (typeLOV != null)
                return typeLOV;

            // is it a type PhysQty?
            // TODO:

            // no type found matching the name
            return null;
        }

        //---------------------------------------------------------------------
        public ITypeBasic FindTypeBasicByName(string name)
        {
            IEnumerable<ITypeBasic> list = _typeMgr.ListTypeBasic;

            foreach (ITypeBasic type in list)
            {
                if (type.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                    return type;
            }

            return null;
        }


        //---------------------------------------------------------------------
        public IType FindTypeById(string idStr)
        {
            if (string.IsNullOrWhiteSpace(idStr))
                return null;

            // is it a type basic?
            ITypeBasic typeBasic = FindTypeBasicById(idStr);
            if (typeBasic != null)
                return typeBasic;

            // not a type basic, is it a type xxx?
            // TODO:

            // not type found matching the id
            return null;
        }

        //---------------------------------------------------------------------
        public ITypeBasic FindTypeBasicById(string idStr)
        {
            IEnumerable<ITypeBasic> list = _typeMgr.ListTypeBasic;

            foreach (ITypeBasic type in list)
            {
                if (type.Id.IdAreEquals(idStr))
                    return type;
            }

            return null;
        }

        //---------------------------------------------------------------------
        public ListType FindListTypeByName(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return null;

            foreach (ListType list in _typeMgr.ListListType)
            {
                if (list.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                    return list;
            }
            return null;
        }

        #endregion

        //=====================================================================
        #region Public Find Enum methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Find a TypeLOV by the name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ITypeEnum FindTypeEnumByName(string name)
        {
            IEnumerable<ITypeEnum> list = _typeMgr.ListTypeEnum;

            foreach (ITypeEnum type in list)
            {
                if (type.Name.Equals(name))
                    return type;
            }

            return null;
        }

        //---------------------------------------------------------------------
        public ITypeEnumString FindTypeEnumStringByName(string name)
        {
            ITypeEnum typeLOV = FindTypeEnumByName(name);
            if (typeLOV == null)
                return null;

            return typeLOV as ITypeEnumString;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Find a value in a LOV, return the dataValue.
        /// The type of values must be string.
        /// </summary>
        /// <param name="typeEnum"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public ValueString FindValueInTypeEnum(ITypeEnumString typeEnum, string value)
        {
            if (typeEnum == null)
                return null;
            if (string.IsNullOrWhiteSpace(value))
                return null;

            foreach (ValueString dv in typeEnum.ListDValItems)
            {
                if (dv.IsEqualsTo(value))
                    return dv;
            }

            return null;
        }

        #endregion

        //=====================================================================
        #region Public Contains methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Return true if the typeLOV is contained in the type manager.
        /// </summary>
        /// <param name="typeEnumFind"></param>
        /// <returns></returns>
        public bool ContainsTypeEnum(ITypeEnum typeEnumFind)
        {
            if (typeEnumFind == null)
                return false;

            foreach (ITypeEnum typeEnum in _typeMgr.ListTypeEnum)
            {
                if (typeEnumFind == typeEnum)
                    return true;
            }
            return false;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Return true if thez typeLOV stirng contains the item (a string).
        /// </summary>
        /// <param name="typeEnum"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool TypeEnumContains(ITypeEnumString typeEnum, string item)
        {
            if (typeEnum == null)
                return false;
            if (string.IsNullOrWhiteSpace(item))
                return false;

            // scan all items
            foreach (ValueString s in typeEnum.ListDValItems)
            {
                if (s.GetValue().Equals(item, StringComparison.InvariantCultureIgnoreCase))
                    // item is present in the typeLOV
                    return true;
            }

            // not present
            return false;
        }

        #endregion

    }
}
